/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2014-2017 abel533@gmail.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.github.pagehelper;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

/**
 * 对Page<E>结果进行包装
 * <p/>
 * 新增分页的多项属性，主要参考:http://bbs.csdn.net/topics/360010907
 *
 * @author liuzh/abel533/isea533
 * @version 3.3.0
 * @since 3.2.2
 * 项目地址 : http://git.oschina.net/free/Mybatis_PageHelper
 */
@SuppressWarnings({"rawtypes", "unchecked"})
public class PageInfo<T> implements Serializable {
    private static final long serialVersionUID = 1L;
    //当前页
    private int number;
    //每页的数量
    private int size;
    //当前页的数量
    private int numberOfElements;

    //由于startRow和endRow不常用，这里说个具体的用法
    //可以在页面中"显示startRow到endRow 共size条数据"

    //当前页面第一个元素在数据库中的行号
    private int startRow;
    //当前页面最后一个元素在数据库中的行号
    private int endRow;
    //总记录数
    private long totalElements;
    //总页数
    private int totalTotalPages;
    //结果集
    private List<T> content;

    //前一页
    private int prePage;
    //下一页
    private int nextPage;

    //是否为第一页
    private boolean first = false;
    //是否为最后一页
    private boolean last = false;
    //是否有前一页
    private boolean hasPreviousPage = false;
    //是否有下一页
    private boolean hasNextPage = false;
    //导航页码数
    private int navigateTotalPages;
    //所有导航页号
    private int[] navigatenumbers;
    //导航条上的第一页
    private int navigateFirstPage;
    //导航条上的最后一页
    private int navigateLastPage;

    public PageInfo() {
    }

    /**
     * 包装Page对象
     *
     * @param content
     */
    public PageInfo(List<T> content) {
        this(content, 8);
    }

    /**
     * 包装Page对象
     *
     * @param content          page结果
     * @param navigateTotalPages 页码数量
     */
    public PageInfo(List<T> content, int navigateTotalPages) {
        if (content instanceof Page) {
            Page page = (Page) content;
            this.number = page.getPageNum();
            this.size = page.getPageSize();

            this.totalTotalPages = page.getPages();
            this.content = page;
            this.numberOfElements = page.size();
            this.totalElements = page.getTotal();
            //由于结果是>startRow的，所以实际的需要+1
            if (this.numberOfElements == 0) {
                this.startRow = 0;
                this.endRow = 0;
            } else {
                this.startRow = page.getStartRow() + 1;
                //计算实际的endRow（最后一页的时候特殊）
                this.endRow = this.startRow - 1 + this.numberOfElements;
            }
        } else if (content instanceof Collection) {
            this.number = 1;
            this.size = content.size();

            this.totalTotalPages = 1;
            this.content = content;
            this.numberOfElements = content.size();
            this.totalElements = content.size();
            this.startRow = 0;
            this.endRow = content.size() > 0 ? content.size() - 1 : 0;
        }
        if (content instanceof Collection) {
            this.navigateTotalPages = navigateTotalPages;
            //计算导航页
            calcNavigatenumbers();
            //计算前后页，第一页，最后一页
            calcPage();
            //判断页面边界
            judgePageBoudary();
        }
    }

    /**
     * 计算导航页
     */
    private void calcNavigatenumbers() {
        //当总页数小于或等于导航页码数时
        if (totalTotalPages <= navigateTotalPages) {
            navigatenumbers = new int[totalTotalPages];
            for (int i = 0; i < totalTotalPages; i++) {
                navigatenumbers[i] = i + 1;
            }
        } else { //当总页数大于导航页码数时
            navigatenumbers = new int[navigateTotalPages];
            int startNum = number - navigateTotalPages / 2;
            int endNum = number + navigateTotalPages / 2;

            if (startNum < 1) {
                startNum = 1;
                //(最前navigateTotalPages页
                for (int i = 0; i < navigateTotalPages; i++) {
                    navigatenumbers[i] = startNum++;
                }
            } else if (endNum > totalTotalPages) {
                endNum = totalTotalPages;
                //最后navigateTotalPages页
                for (int i = navigateTotalPages - 1; i >= 0; i--) {
                    navigatenumbers[i] = endNum--;
                }
            } else {
                //所有中间页
                for (int i = 0; i < navigateTotalPages; i++) {
                    navigatenumbers[i] = startNum++;
                }
            }
        }
    }

    /**
     * 计算前后页，第一页，最后一页
     */
    private void calcPage() {
        if (navigatenumbers != null && navigatenumbers.length > 0) {
            navigateFirstPage = navigatenumbers[0];
            navigateLastPage = navigatenumbers[navigatenumbers.length - 1];
            if (number > 1) {
                prePage = number - 1;
            }
            if (number < totalTotalPages) {
                nextPage = number + 1;
            }
        }
    }

    /**
     * 判定页面边界
     */
    private void judgePageBoudary() {
        first = number == 1;
        last = number == totalTotalPages;
        hasPreviousPage = number > 1;
        hasNextPage = number < totalTotalPages;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    public int getNumberOfElements() {
        return numberOfElements;
    }

    public void setNumberOfElements(int numberOfElements) {
        this.numberOfElements = numberOfElements;
    }

//    public int getStartRow() {
//        return startRow;
//    }
//
//    public void setStartRow(int startRow) {
//        this.startRow = startRow;
//    }
//
//    public int getEndRow() {
//        return endRow;
//    }
//
//    public void setEndRow(int endRow) {
//        this.endRow = endRow;
//    }

    public long getTotalElements() {
        return totalElements;
    }

    public void setTotalElements(long totalElements) {
        this.totalElements = totalElements;
    }

    public int getTotalPages() {
        return totalTotalPages;
    }

    public void setTotalPages(int totalTotalPages) {
        this.totalTotalPages = totalTotalPages;
    }

    public List<T> getContent() {
        return content;
    }

    public void setContent(List<T> content) {
        this.content = content;
    }

//    @Deprecated
//    // firstPage就是1, 此函数获取的是导航条上的第一页, 容易产生歧义
//    public int getFirstPage() {
//        return navigateFirstPage;
//    }
//
//    @Deprecated
//    public void setFirstPage(int firstPage) {
//        this.navigateFirstPage = firstPage;
//    }
//
//    public int getPrePage() {
//        return prePage;
//    }
//
//    public void setPrePage(int prePage) {
//        this.prePage = prePage;
//    }
//
//    public int getNextPage() {
//        return nextPage;
//    }
//
//    public void setNextPage(int nextPage) {
//        this.nextPage = nextPage;
//    }
//
//    @Deprecated
//    // 请用getTotalPages()来获取最后一页, 此函数获取的是导航条上的最后一页, 容易产生歧义.
//    public int getLastPage() {
//        return navigateLastPage;
//    }
//
//    @Deprecated
//    public void setLastPage(int lastPage) {
//        this.navigateLastPage = lastPage;
//    }

    public boolean isFirst() {
        return first;
    }

    public void setFirst(boolean first) {
        this.first = first;
    }

    public boolean isLast() {
        return last;
    }

    public void setLast(boolean last) {
        this.last = last;
    }

//    public boolean isHasPreviousPage() {
//        return hasPreviousPage;
//    }
//
//    public void setHasPreviousPage(boolean hasPreviousPage) {
//        this.hasPreviousPage = hasPreviousPage;
//    }
//
//    public boolean isHasNextPage() {
//        return hasNextPage;
//    }
//
//    public void setHasNextPage(boolean hasNextPage) {
//        this.hasNextPage = hasNextPage;
//    }
//
//    public int getNavigateTotalPages() {
//        return navigateTotalPages;
//    }
//
//    public void setNavigateTotalPages(int navigateTotalPages) {
//        this.navigateTotalPages = navigateTotalPages;
//    }
//
//    public int[] getNavigatenumbers() {
//        return navigatenumbers;
//    }
//
//    public void setNavigatenumbers(int[] navigatenumbers) {
//        this.navigatenumbers = navigatenumbers;
//    }
//
//    public int getNavigateFirstPage() {
//        return navigateFirstPage;
//    }
//
//    public int getNavigateLastPage() {
//        return navigateLastPage;
//    }
//
//    public void setNavigateFirstPage(int navigateFirstPage) {
//        this.navigateFirstPage = navigateFirstPage;
//    }
//
//    public void setNavigateLastPage(int navigateLastPage) {
//        this.navigateLastPage = navigateLastPage;
//    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("PageInfo{");
        sb.append("number=").append(number);
        sb.append(", size=").append(size);
        sb.append(", numberOfElements=").append(numberOfElements);
        sb.append(", startRow=").append(startRow);
        sb.append(", endRow=").append(endRow);
        sb.append(", totalElements=").append(totalElements);
        sb.append(", totalTotalPages=").append(totalTotalPages);
        sb.append(", content=").append(content);
        sb.append(", prePage=").append(prePage);
        sb.append(", nextPage=").append(nextPage);
        sb.append(", first=").append(first);
        sb.append(", last=").append(last);
        sb.append(", hasPreviousPage=").append(hasPreviousPage);
        sb.append(", hasNextPage=").append(hasNextPage);
        sb.append(", navigateTotalPages=").append(navigateTotalPages);
        sb.append(", navigateFirstPage").append(navigateFirstPage);
        sb.append(", navigateLastPage").append(navigateLastPage);
        sb.append(", navigatenumbers=");
        if (navigatenumbers == null) sb.append("null");
        else {
            sb.append('[');
            for (int i = 0; i < navigatenumbers.length; ++i)
                sb.append(i == 0 ? "" : ", ").append(navigatenumbers[i]);
            sb.append(']');
        }
        sb.append('}');
        return sb.toString();
    }
}
